<?php

namespace Bundle\TreeBundle;

use Bundle\TreeBundle\Interfaces;

class TreeManager {

    private $entityPath = 'Bundle\\TreeBundle\\Entities\\Tree';
    /**
     * Менеджер сущностей
     * @var Doctrine\ORM\EntityManager
     */
    protected $entityManager;

    /**
     * Конструктор.
     * @param Doctrine\ORM\EntityManager $manager
     */
    public function __construct(\Doctrine\ORM\EntityManager $manager) {
        $this->entityManager = $manager;
    }

    /**
     * Поиск дерева по ключу
     * @param <type> $id
     * @return <type>
     */
    public function getTree($id) {
        return $this->entityManager->find($this->entityPath, $id);
    }

    /**
     * Поиск поддеревьев
     * @param <type> $id
     * @return <type>
     */
    public function getSubtrees($id) {
        $query = $this->entityManager->createQueryBuilder()->select('t')
                        ->from($this->entityPath, 't')
                        ->where("t.parentlist LIKE '%;$id;%'")
                        ->orWhere("t.id = $id")
                        //->setParameter(':id', $id)
                        ->getQuery();
        return $query->getResult();
    }

    /**
     * Удаление дерева по ключу
     * Сначала удаляются все поддеревья, затем само дерево
     * @param <type> $id
     */
    public function deleteTree($id) {

        $query = $this->entityManager->createQueryBuilder()->delete($this->entityPath, 't');
        $result = $query->where('t.id = ' . $id)
                        ->orWhere("t.parentlist LIKE '%;$id;%'")
                        //->setParameter(':id', $id)->
                        ->getQuery()->execute();
        return $result;
    }

    /**
     * Установка изменение родителя у дерева
     * @param <type> $parentid
     * @param <type> $treeid 
     */
    public function setParent($parentid, $treeid) {
        $parentlist = '';
        if ($parentid == -1) {
            $parentlist = ';-1;';
        } else {
            $parent = $this->getTree($parentid);
            $parentlist = $parent->getParentlist();
        }
        \var_dump($parentlist);

        $tree = $this->getTree($treeid);

        $query = $this->entityManager->createQueryBuilder()->update($this->entityPath, 't');

        $from_str = "\';{$tree->getId()}{$tree->getParentlist()}\'";
        $to_str = "\';{$tree->getId()}{$parentlist}\'";

        \var_dump($from_str);
        \var_dump($to_str);

        $query->set('t.parentlist', 'REPLACE(t.parentlist,' . $from_str . ', ' . $to_str . ')')
                ->where("t.parentlist LIKE '%;:id;%")
                ->setParameter(':id', $tree->getId() . $tree->getParentlist());


        //die(\var_dump($query->getDQL()));

        \var_dump($result = $query->getQuery()->execute());

        $tree->setParentid($parentid);
        if ($parentid == -1)
            $tree->setParentlist(';-1;');
        else
            $tree->setParentlist(';' . $parent->getId() . $parentlist);

        $this->entityManager->persist($tree);
    }

    /**
     * Построение иерархии деревьев с учётом приоритета отображения
     * @param array of Tree $trees
     * @param int $parentid
     */
    public static function buildForest($trees, $parentid = -1) {

        $forest = array();
        
        foreach ($trees as $tree)
        {
            if ($tree->getId() == $parentid || $tree->getParent() == -1)
            {
                $forest[$tree->getId()] = array
                    (
                    'root' => $tree,
                    'leaves' => array(),
                );
            } 
            else
            {
                $parents = \array_reverse(\explode(';', \trim($tree->getParentlist(), ';')));
                //die(\var_dump($parents));
                $walker = &$forest;
                for ($i = 1; $i <= \count($parents) - 1; $i++) {
                    
                    if (!\array_key_exists($parents[$i], $walker)) {
                        $walker[$parents[$i]] = array(
                            'root' => null,
                            'leaves' => array()
                        );
                    }
                    $walker = &$walker[$parents[$i]]['leaves'];
                }
                $walker[$tree->getId()] = array
                    (
                    'root' => $tree,
                    'leaves' => array(),
                );
            }
        }
        return $forest;
    }


    /**
     * Создание дерева, с указанием родительского
     * @param Bundle\TreeBundle\Entities\Tree $tree сущность которую надо создать
     */
    public function createTree(\Bundle\TreeBundle\Entities\Tree $tree)
    {
        if($tree->getParent() != -1)
        {
            $parentTree = $this->getTree($tree->getParent());
            $tree->setParentlist($parentTree->getParentlist());
        }
        $tree->setParentlist(';' . $tree->getParent() . $tree->getParentlist());

        $this->entityManager->persist($tree);
        $this->entityManager->flush();
    }

//
//
//
//    /**
//     * Значение ключа дерева
//     */
//    var $key;
//
//    /**
//     * Значение приоритета
//     */
//    var $order;
//
//    /**
//     *
//     * @var Doctrine\ORM\EntityManager
//     */
//    var $repo;
//    /**
//     * Получение дерева из базы
//     * @param TreePersistantRulesInterface $rules
//     * @param <type> $key
//     * @return Tree
//     */
//    public static function getTree($repo, $key)
//    {
//        return new TreeStorage($repo);
//    }
//
//
//    /**
//     * Установка ключа дерева
//     * @param <type> $key
//     */
//    public function setKey($key)
//    {
//        $this->key = $key;
//    }
//
//    /**
//     * Получение ключа дерева
//     * @return <type>
//     */
//    public function getKey()
//    {
//        return $this->key;
//    }
//
//    /**
//     * Установка приоритета
//     * @param <type> $order
//     */
//    public function setOrder($order)
//    {
//        $this->order = $order;
//    }
//    /**
//     * Получение приоритета
//     * @return <type>
//     */
//    public function getOrder()
//    {
//        return $this->order;
//    }
//
//    /**
//     * Получение поддеревьев
//     * @return array of Tree
//     */
//    public function getSubTrees()
//    {
//        $this->key = -1; // @TODO !!
//        $qb = $this->repo->createQueryBuilder()
//                ->select('t')
//                ->from('Bundle\\TreeBundle\\Entities\\Tree', 't')
//                ->where('t.parentlist LIKE \'%;' . $this->key . ';%\'')
//                ->orderBy('t.order', 'ASC');
//        $query = $qb->getQuery();
//        return $query->getResult();
//    }
//
//    /**
//     * Удаление поддеревьев
//     */
//    public function removeSubTrees()
//    {
//
//    }
//
//    /**
//     * Построение структурированного массива отображающего дерево
//     * @return <type>
//     */
//    public function buildForest()
//    {
//        //@TODO реализовать работу с кэшем
//        $trees_d = $this->getSubTrees();
//
//        //die(var_dump($trees_d));
//        $trees = array();
//        foreach($trees_d as $tree_d)
//        {
//            if($tree_d->getParent() == -1)
//            {
//                $trees[$tree_d->getId()] = array('root' => $tree_d, 'leaves' => array());
//            }
//            else
//            {
//
//                $parents = \array_reverse(\explode(';', \trim($tree_d->getParentlist(),';')));
//                $trz_tmp = &$trees;
//                for($i = 0; $i < \count($parents) - 1; $i++)
//                {
//                    if(!\array_key_exists($parents[$i], $trz_tmp))
//                    {
//                        $trz_tmp[$parents[$i]] = array('root' => null, 'leaves' => array());
//                    }
//                    $trz_tmp = &$trz_tmp[$parents[$i]]['leaves'];
//                }
//                $trz_tmp[$tree_d->getId()] = array('root' => $tree_d, 'leaves' => array());
//            }
//        }
//
//        return $trees;
//
//    }
//
//
//    /**
//     * Добавление поддерева
//     * @param Tree $subtree
//     */
//    public function addSubTree(Tree $subtree)
//    {
//
//    }
//
//    public function getLeaf(TreeValueInterface $key)
//    {
//
//    }
//
//    public function deleteLeaf(TreeValueInterface $key)
//    {
//
//    }
//
//    public function createLeaf(TreeValueInterface $key, TreeValueInterface $parent = null)
//    {
//
//    }
//
//    /*
//     * @TODO методы модификации дерева...
//     */
//
//
}

